package com.dazzle.cameralib;


import android.annotation.TargetApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.util.Size;

import com.dazzle.cameralib.utils.DebugUtils;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class CameraRecordService extends Service {

    public static final String TAG = "CameraRecordService";

    public static final int _720P_WIDTH  = 1280;
    public static final int _720P_HEIGHT = 720;

    private Context mContext;
    private final boolean enableGetOptimalSize = false;

    private FloatPreviewWindow floatPreviewWindow;
    private MediaRecorder mMediaRecorder;
    private File mOutputFile;
    private Camera mCamera;

    /**
     * camer Params
     */
    private Size previewSize;
    private Size pictureSize;
    private Size videoSize;
    private Rect previewRect;

    /**
     * camera status
     */
    private boolean isPreviewEnable = false;
    private boolean isPreviewHide = false;
    private boolean isRecording = false;


    private final ICameraRecoderInterface.Stub mBinder = new ICameraRecoderInterface.Stub() {

        public boolean enablePreview(boolean enable) {
            if (enable) {
                return doStartPreview();
            } else {
                return doStopPreview();
            }
        }

        public  boolean enableRecord(boolean enable) {
            if (enable) {
                return doStarRecord();
            } else {
                return doStopRecord();
            }
        }

        public boolean isPreviewEnable() {
            return isPreviewEnable;
        }

        public boolean isRecoreding() {
            return isRecording;
        }

        public boolean isPreviewHide() {
            return isPreviewHide;
        }

        public void hidePreviewWindow() {
            floatPreviewWindow.hideFloatView();
            isPreviewHide = true;
        }
        public void showPreviewWindow() {
            floatPreviewWindow.showFloatView();
            isPreviewHide = false;
        }

        public void doSetVideoSize(int w, int h) {
            Size size = new Size(w, h);
            setPreviewSize(size);
            setVideoSize(size);
            setPictureSize(size);
        }

        public void doSetWindowRect(int left, int top, int right, int bottom) {
            Rect rect = new Rect(left, top, right, bottom);
            floatPreviewWindow.setFloatViewRect(rect);
        }

    };

    @Override
    public void onCreate() {
        DebugUtils.LogE(TAG, "server onCreate");
        super.onCreate();
        mContext = this;

        previewSize = new Size(_720P_WIDTH, _720P_HEIGHT);
        pictureSize = new Size(_720P_WIDTH, _720P_HEIGHT);
        videoSize   = new Size(_720P_WIDTH, _720P_HEIGHT);

        previewRect = new Rect(1920-_720P_WIDTH, 1080-_720P_HEIGHT, 1920, 1080);

        if (floatPreviewWindow == null) {
            floatPreviewWindow = new FloatPreviewWindow(mContext, previewRect);
        }
        floatPreviewWindow.createFloatView();
    }


    @Override
    public void onDestroy() {
        DebugUtils.LogE(TAG, "server onDestroy");
        super.onCreate();
        releaseMediaRecorder();
        closeCamera();
        floatPreviewWindow.removeWindow();
    }

    @Override
    public boolean onUnbind(Intent intent){
        return true;
    }

    @Override
    public IBinder onBind(Intent intent) {
        DebugUtils.LogE(TAG, "server on bind");
        return mBinder;
    }

    private void releaseMediaRecorder(){
        if (mMediaRecorder != null) {
            // clear recorder configuration
            mMediaRecorder.reset();
            // release the recorder object
            mMediaRecorder.release();
            mMediaRecorder = null;
            // Lock camera for later use i.e taking it back from MediaRecorder.
            // MediaRecorder doesn't need it anymore and we will release it if the activity pauses.
            mCamera.lock();
        }
    }

    private void openCamera() {
        if (mCamera == null) {
            mCamera = CameraHelper.getDefaultCameraInstance();
        }
    }

    private void closeCamera() {
        if (mCamera != null){
            // release the camera for other applications
//            mCamera.unlock();
            mCamera.release();
            mCamera = null;
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private boolean prepareVideoRecorder(){
        if (!initCameraParames()) {
            return false;
        }

        CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
        profile.videoFrameWidth = videoSize.getWidth();
        profile.videoFrameHeight = videoSize.getHeight();

        mMediaRecorder = new MediaRecorder();

        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);

        // Step 2: Set sources
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT );
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
        mMediaRecorder.setProfile(profile);

        // Step 4: Set output file
        mOutputFile = CameraHelper.getOutputMediaFile(CameraHelper.MEDIA_TYPE_VIDEO);
        if (mOutputFile == null) {
            return false;
        }
        mMediaRecorder.setOutputFile(mOutputFile.getPath());
        // END_INCLUDE (configure_media_recorder)

        // Step 5: Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }

        return true;
    }

    /**
     * 开始录像，未打开预览也会打开预览
     * @return true - success
     *          false  - fail
     */
    private boolean doStarRecord() {
        if (isRecording) {
            DebugUtils.LogE(TAG, "Stop Record fail, it is running");
            return false;
        }
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared,
            // now you can start recording
            mMediaRecorder.start();
            isRecording = true;
            isPreviewEnable = true;
            return true;
        } else {
            return false;
        }
    }

    /**
     * 停止录像，不会停止预览
     * @return true - success
     *          false - fail
     */
    private boolean doStopRecord() {
        boolean ret = true;
        if (!isRecording) {
            DebugUtils.LogE(TAG, "Stop Record fail, it is not running");
            return false;
        }
        try {
            mMediaRecorder.stop();  // stop the recording
        } catch (RuntimeException e) {
            // RuntimeException is thrown when stop() is called immediately after start().
            // In this case the output file is not properly constructed ans should be deleted.
            Log.d(TAG, "RuntimeException: stop() is called immediately after start()");
            //noinspection ResultOfMethodCallIgnored
            mOutputFile.delete();
            ret = false;
        }
        releaseMediaRecorder(); // release the MediaRecorder object
        mCamera.lock();         // take camera access back from MediaRecorder
        // inform the user that recording has stopped
        isRecording = false;
        return ret;
    }


    /**
     * 使用TextureView预览Camera
     */
    private boolean doStartPreview(){
        Log.i(TAG, "doStartPreview...");
        if (isPreviewEnable) {
            DebugUtils.LogE(TAG, "doStartPreview fail, it is running");
            return false;
        }
        if(initCameraParames()) {
            mCamera.startPreview();//开启预览
            isPreviewEnable = true;
            return true;
        }
        return false;
    }

    /**
     * 停止TextureView预览Camera
     */
    private boolean doStopPreview(){
        Log.i(TAG, "doStartPreview...");
        if (isRecording) {
            DebugUtils.LogE(TAG, "can't stop preview, because is recording fail");
            return false;
        }

        if (!isPreviewEnable) {
            DebugUtils.LogE(TAG, "doStartPreview fail, it is  not running");
            return false;
        }
        if(mCamera != null) {
            mCamera.stopPreview();//停止
            isPreviewEnable = false;
        }
        closeCamera();
        return true;
    }


    public void setPreviewSize(Size size) {
        previewSize  = size;
    }

    public void setPictureSize(Size size) {
        pictureSize  = size;
    }

    public void setVideoSize(Size size) {
        videoSize  = size;
    }

    public Size getOptimalSize(Size viewSize) {
        if (mCamera != null) {
            Camera.Parameters mParams = mCamera.getParameters();
            List<Camera.Size> mSupportedPreviewSizes = mParams.getSupportedPreviewSizes();
            List<Camera.Size> mSupportedVideoSizes = mParams.getSupportedVideoSizes();
            Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
                    mSupportedPreviewSizes, viewSize.getWidth(), viewSize.getHeight());
            return new Size(optimalSize.width, optimalSize.height);
        } else {
            DebugUtils.LogE(TAG, "getOptimalSize fail, set default size 720P, camera no open");
            return new Size(_720P_WIDTH, _720P_HEIGHT);
        }
    }

    private boolean initCameraParames() {
        boolean ret = false;
        if (mCamera == null) {
            openCamera();
        }

        if (mCamera != null) {
            try {
                mCamera.setPreviewTexture(floatPreviewWindow.getCameraTextureView()._getSurfaceTexture());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            Camera.Parameters mParams = mCamera.getParameters();
            mParams.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式

            Size viewSize = new Size(floatPreviewWindow.getCameraTextureView().getWidth(),
                    floatPreviewWindow.getCameraTextureView().getHeight());

            if (enableGetOptimalSize) {
                Size optimalSize = getOptimalSize(viewSize);
                setVideoSize(optimalSize);
                setPictureSize(optimalSize);
                setPreviewSize(optimalSize);
            }
            mParams.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
            mParams.setPictureSize(pictureSize.getWidth(), pictureSize.getWidth());

            List<String> focusModes = mParams.getSupportedFocusModes();
            if(focusModes.contains("continuous-video")){
                mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }

            mCamera.setParameters(mParams);

            ret = true;
        } else {
            DebugUtils.LogE(TAG, "init Camera Parames fail, camera is null");
        }
        return ret;
    }

    private boolean initMediaCoderParames() {
        return true;
    }
}
